package gitlet;

import java.io.File;
import java.util.*;

import static gitlet.Repository.*;

public class Main {

    public static void main(String[] args) {
        if (args.length == 0) {
            System.out.println("Please enter a command.");
            return;
        }
        String firstArg = args[0];
        Repository repo = null;
        //init done
        //other not in an....
        //
        if (!args[0].equals("init")) {
            if (GITLET_DIR.exists()) {
                repo = Repository.fromFile();
            } else {
                System.out.println("Not in an initialized Gitlet directory.");
                return;
            }
        }
        switch (firstArg) {
            case "init":
                if (!GITLET_DIR.exists()) {
                    GITLET_DIR.mkdir();
                    GITLET_DIR_OBJECT.mkdir();
                    GITLET_DIR_OBJECT_BLOBS.mkdir();
                    HashMap<String, String> newAdd = new HashMap<>();
                    ArrayList<String> newRemove = new ArrayList<>();
                    Commit initialCommit = new Commit("initial commit",
                            null, null, "Wed Dec 31 16:00:00 1969 -0800", newAdd, newRemove);
                    String initialCommitID = initialCommit.getCommitID();
                    Repository newRepo = new Repository(initialCommitID);
                    initialCommit.saveCommit();
                    newRepo.saveRepository();
                } else {
                    System.out.println("A Gitlet version-control system already exists in the current directory.");
                }
                break;
            case "add":
                repo.add(args[1]);
                repo.saveRepository();
                break;

            case "commit":
                if (args.length == 1 || Objects.equals(args[1], "")) {
                    System.out.println("Please enter a commit message.");
                    break;
                }
                repo.makeCommit(args[1], null);
                break;
            case "rm":
                repo.remove(args[1]);
                break;
            case "log":
                //没有merge的情况
                String currCommitIDLog = repo.getBranches().get(repo.getHead());
                while (currCommitIDLog != null) {
                    Commit currentCommit = Commit.fromFile(currCommitIDLog);
                    String currentTimeStamp = currentCommit.getTimeStamp();
                    System.out.println("===");
                    System.out.println("commit " + currCommitIDLog);
                    if (currentCommit.getParent2() != null) {
                        System.out.println("Merge:" + " " + currentCommit.getParent().substring(0, 7) + " " + currentCommit.getParent2().substring(0, 7));
                    }
                    System.out.println("Date: " + currentTimeStamp);
                    System.out.println(currentCommit.getMessage());
                    System.out.println();
                    currCommitIDLog = currentCommit.getParent();
                }
                break;
            //break haofanren
            case "global-log":
                //遍历整个GITLET_DIR_OBJECT)
                List<String> allFile = Utils.plainFilenamesIn(GITLET_DIR_OBJECT);
                if (allFile != null) {
                    for (String fileIDDir : allFile) {
                        Commit currentCommit = Commit.fromFile(fileIDDir);
                        String currentTimeStamp = currentCommit.getTimeStamp();
                        System.out.println("===");
                        System.out.println("commit " + fileIDDir);
                        System.out.println("Date: " + currentTimeStamp);
                        System.out.println(currentCommit.getMessage());
                        System.out.println();

                    }
                }
                break;
            case "find":
                List<String> allFileFind = Utils.plainFilenamesIn(GITLET_DIR_OBJECT);
                boolean found = false;
                if (allFileFind != null) {
                    for (String fileIDDir : allFileFind) {
                        Commit currentCommit = Commit.fromFile(fileIDDir);
                        String currentMessage = currentCommit.getMessage();
                        if (Objects.equals(currentMessage, args[1])) {
                            System.out.println(fileIDDir);
                            found = true;
                        }
                    }
                }
                if (!found) {
                    System.out.println("Found no commit with that message.");
                }
                break;
            case "status":
                System.out.println("=== Branches ===");
                List<String> keys = new ArrayList<>(repo.getBranches().keySet());
                Collections.sort(keys);
                for (String key : keys) {
                    if (Objects.equals(repo.getHead(), key)) {
                        System.out.println("*" + key);
                    } else {
                        System.out.println(key);
                    }
                }
                System.out.println();
                System.out.println("=== Staged Files ===");
                for (String key : repo.getStagingArea().getAddition().keySet()) {
                    System.out.println(key);
                }
                System.out.println();
                System.out.println("=== Removed Files ===");
                for (String key : repo.getStagingArea().getRemove()) {
                    System.out.println(key);
                }
                System.out.println();
                System.out.println("=== Modifications Not Staged For Commit ===");
                System.out.println();
                System.out.println("=== Untracked Files ===");
                System.out.println();

                break;
            case "checkout":
                //java gitlet.Main checkout [commit id] -- [file name]
                if (args.length == 4) {
                    if (!Objects.equals(args[2], "--")) {
                        System.out.println("Incorrect operands.");
                        break;
                    }
                    repo.checkout2(args[1], args[3]);
                    break;
                } else if (args.length == 3) {
                    //java gitlet.Main checkout -- [file name]
                    if (!Objects.equals(args[1], "--")) {
                        System.out.println("Incorrect operands.");
                        break;
                    }
                    repo.checkout2(repo.getBranches().get(repo.getHead()), args[2]);
                    break;
                } else {
                    //java gitlet.Main checkout [branch name]
                    HashMap<String, String> branch = repo.getBranches();
                    if (!branch.containsKey(args[1])) {
                        System.out.println("No such branch exists.");
                        break;
                    }
                    if (repo.checkout3(args[1]) == 0) ;
                    {
                        repo.setHead(args[1]);
                        repo.saveRepository();
                    }
                    break;
                }
            case "branch":
                if (repo.getBranches().containsKey(args[1])) {
                    System.out.println("A branch with that name already exists.");
                } else {
                    currCommitIDLog = repo.getBranches().get(repo.getHead());
                    repo.getBranches().put(args[1], currCommitIDLog);
                    repo.saveRepository();
                }
                break;


            case "rm-branch":
                if (!repo.getBranches().containsKey(args[1])) {
                    System.out.println("A branch with that name does not exist.");
                } else if (Objects.equals(args[1], repo.getHead())) {
                    System.out.println("Cannot remove the current branch.");
                } else {
                    repo.getBranches().remove(args[1]);
                    repo.saveRepository();
                }
                break;
            case "reset":
                String rightID = Commit.getUniqueIDIfExist(args[1]);
                if (rightID == null) {
                    System.out.println(" No commit with that id exists.");
                    break;
                }
                File s = new File(GITLET_DIR_OBJECT, rightID);
                if (!s.exists()) {
                    System.out.println("No commit with that id exists.");
                } else {
                    Commit resetCommitID = Commit.fromFile(rightID);
                    Commit headCommitID = Commit.fromFile(repo.getBranches().get(repo.getHead()));
                    boolean errorfound = false;
                    for (String fileName : resetCommitID.fileList.keySet()) {
                        File sReset = new File(CWD, fileName);
                        if (!headCommitID.fileList.containsKey(fileName)) {
                            if (sReset.exists()) {
                                errorfound = true;
                            }
                        }
                    }
                    if (errorfound) {
                        System.out.println("There is an untracked file"
                                + " in the way; delete it, or add and commit it first.");
                        break;
                    }
                    for (HashMap.Entry<String, String> entry : resetCommitID.fileList.entrySet()) {
                        File t = new File(CWD, entry.getKey());
                        Utils.writeContents(t, Blob.fromFile(entry.getValue()).getData());
                    }
                    String currentbranchCommit = repo.getBranches().get(repo.getHead());
                    Commit currentBranchCommitID = Commit.fromFile(currentbranchCommit);
                    for (String key : currentBranchCommitID.fileList.keySet()) {
                        if (!resetCommitID.fileList.containsKey(key)) {
                            File t = new File(CWD, key);
                            Utils.restrictedDelete(t);
                        }
                    }
                    repo.getStagingArea().getRemove().clear();
                    repo.getStagingArea().getAddition().clear();
                    String head = repo.getHead();
                    repo.getBranches().put(head, rightID);
                    repo.saveRepository();
                }
                break;
            case "merge":
                //java gitlet.Main merge [branch name]
                if (!repo.getStagingArea().getAddition().isEmpty() || (!repo.getStagingArea().getRemove().isEmpty())) {
                    System.out.println("You have uncommitted changes.");
                    break;
                }
                if (!repo.getBranches().containsKey(args[1])) {
                    System.out.println("A branch with that name does not exist.");
                    break;
                }
                if (repo.getHead().equals(args[1])) {
                    System.out.println("Cannot merge a branch with itself.");
                    break;
                }
                MergeUtils.handleMerge(repo, args[1]);


                break;
            default:
                System.out.println("No command with that name exists.");
        }
    }
}

